package model;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
 
/**
 * A data structure of a piece of configuration file "configuration.gz", we named
 * it configuration element.
 */
public class ConfigElem {
	
	/** the index of this piece of configuration */
	private int index;
	
	/** the number of hexanol molecule */
	private int hexanolNum;
	
	/** the number of water molecule */
	private int waterNum;
	
	/** 
	 * the list of molecule models, for configuration element consists of 
	 * molecule models
	 */
	private List<MoleculeModel> list;
	
	/** center of gravity */
	private Float3D cg;
	
	/** group similarity label */
	private int label;
	
	/**
	 * Constructor method. Declared private, so codes cannot use <code>new</code>
	 * method to construct it.
	 */
	private ConfigElem(){
		cg = new Float3D();
	}
	
	/**
	 * Get the index of this piece of configuration.
	 * 
	 * @return the index of this piece of configuration
	 */
	public int getIndex(){
		return index;
	}
	
	/**
	 * set group similarity label
	 * @param label group similarity label
	 */
	public void setLabel(int label){
		this.label = label;
	}
	
	/**
	 * get group similarity label
	 * @return group similarity label
	 */
	public int getLabel(){
		return label;
	}

	
	/**
	 * get center of gravity
	 * @return center of gravity
	 */
	public Float3D getCG(){
		return cg;
	}

	/**
	 * Get the hexanol number of this element.
	 * 
	 * @return the hexanol number of this element
	 */
	public int getHexanolNum(){
		return hexanolNum;
	}

	/**
	 * Get the water number of this element.
	 * 
	 * @return the water number of this element
	 */
	public int getWaterNum(){
		return waterNum;
	}


	/**
	 * Parse configuration file and generate the configuration element.
	 * 
	 * @param reader the buffered reader accesses to configuration file.
	 * 
	 * @return a configuration element
	 * 
	 * @throws IOException if there is some IO exception occur
	 */
	public static ConfigElem parseElement(BufferedReader reader) throws Exception {
		ConfigElem elem = new ConfigElem();
		elem.list = new ArrayList<MoleculeModel>();
		
		String line;
		String[] split;

		line = reader.readLine();
		if(line == null || line.trim().length() == 0){
			return null;
		}
		
		elem.index = Integer.parseInt(line.trim());
		
		line = reader.readLine();
		split = line.trim().split("[\\s]+");
		int total = Integer.parseInt(split[0]);
		elem.waterNum = Integer.parseInt(split[1]);
		elem.hexanolNum = Integer.parseInt(split[2]);
		
		Float3D f3D = new Float3D();
		for(int i = 0; i<total; i++){
			MoleculeModel mm = MoleculeModel.parseMolecule(reader);
			
			f3D.add(mm.accumCoor());
			elem.list.add(mm);
		}
		
		int atomTotal = elem.waterNum * WaterMolecule.ATOM_NUM
				+ elem.hexanolNum * HexanolMolecule.ATOM_NUM;

		elem.cg.x = f3D.x / atomTotal;
		elem.cg.y = f3D.y / atomTotal;
		elem.cg.z = f3D.z / atomTotal;
		
		return elem;
	}

	/**
	 * Store the configuration element in file.
	 * 
	 * @param writer the PrintWriter accesses molecule data file.
	 */
	public void store(PrintWriter writer) {
		writer.println(waterNum*WaterMolecule.ATOM_NUM + hexanolNum*HexanolMolecule.ATOM_NUM);
		
		for(MoleculeModel m: list){
			m.store(writer);
		}
	}
	
	/** 
	 * Check whether two elements is similar.
	 * 
	 * @return true if similar, else false
	 */
	public boolean isSimilar(ConfigElem ce){
		if(cg.x - ce.cg.x > 2 || cg.y - ce.cg.y > 2 || cg.z - ce.cg.z > 2){
			return false;
		}
		
		return true;
	}
}
